package com.pactera.mavenweb.controller;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.dao.DataAccessException;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.authentication.dao.SaltSource;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Controller;

import com.pactera.mavenweb.service.UserDetailsService;
//import com.pactera.mavenweb.service.UserDetailsService;

@Controller
public class LoginAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
	private SaltSource saltSource;
	private PasswordEncoder passwordEncoder = new Md5PasswordEncoder();
	
	protected static Logger logger = Logger.getLogger(LoginAuthenticationProvider.class);
	
	@Resource(name="userDetailsService")
	private UserDetailsService userDetailsService;
	
	@Override
	protected void additionalAuthenticationChecks(UserDetails userDetails,
												UsernamePasswordAuthenticationToken authentication) {
		logger.debug("additionalAuthenticationChecks");
		
		logger.debug("authentication.getCredentials() = " + authentication.getCredentials());
		logger.debug("authentication.getPrincipal() = " + authentication.getPrincipal());
		
		Object salt = null;

		if (this.saltSource != null) {
			salt = this.saltSource.getSalt(userDetails);
		}

		if (authentication.getCredentials() == null) {
			logger.debug("Authentication failed: no credentials provided");

			throw new BadCredentialsException("Bad credentials:" + userDetails);
		}

		String presentedPassword = authentication.getCredentials().toString();
		
//		Md5PasswordEncoder md5 = new Md5PasswordEncoder(); 
		String result = passwordEncoder.encodePassword(presentedPassword, salt);
		
		// this part should be changed.
		if (!passwordEncoder.isPasswordValid(result, presentedPassword, salt)) {
			logger.debug("Authentication failed: password does not match stored value");

			throw new BadCredentialsException("Bad credentials:" + userDetails);
		}
	}

	protected void doAfterPropertiesSet() throws Exception {
//		Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
	}

	protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) {
		UserDetails loadedUser = null;

		try {
			loadedUser = this.userDetailsService.loadUserByUsername(username);
			return loadedUser;
		} catch (UsernameNotFoundException notFound) {
			// do sth first
			throw notFound;
		} catch (DataAccessException accessExc) {
			// do sth first
			throw accessExc;
		} catch (Exception repositoryProblem) {
			// perhaps we don't need this
			throw new AuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
		}
		
		
	}
	
	protected PasswordEncoder getPasswordEncoder() {
		return passwordEncoder;
	}

	protected SaltSource getSaltSource() {
		return saltSource;
	}
	
	public void setSaltSource(SaltSource saltSource) {
		this.saltSource = saltSource;
	}
	
	public UserDetailsService getUserDetailsService() {
		return userDetailsService;
	}

	public void setUserDetailsService(UserDetailsService userDetailsService) {
		this.userDetailsService = userDetailsService;
	}
}
